<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>【翻译】什么是 web 框架？ | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="【翻译】什么是 web 框架？ | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2015/09/21/what-is-a-web-framework/">

	
	<meta property="article:published_time" content="2015-09-21T00:09:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2015/09/21/what-is-a-web-framework/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2015-09-20T16:00:00.000Z" itemprop="datePublished">
                    2015-09-21
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/blog/">blog</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">【翻译】什么是 web 框架？</h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <p>原文地址： <a href="http://jeffknupp.com/blog/2014/03/03/what-is-a-web-framework/" target="_blank" rel="noopener">http://jeffknupp.com/blog/2014/03/03/what-is-a-web-framework/</a></p>
<p>Web 应用框架，简称为 <code>web 框架</code>，是编写 web 应用程序的基石。不管简单的博客系统，还是 Ajax 为主的应用，网络上所有的页面都是代码构成的。进来我发现，很多想学习诸如 Flask 或者 Django 等 web 框架的开发者，并不很了解 web 框架是什么，它们的作用和工作原理。这篇文章，我将会讲一下这个通常会被忽略的话题。希望读完这篇文章，你能比较深刻地理解 web 框架到底是什么，还有为什么会有 web 框架。这些知识将有利于你学习新的 web 框架，而且在选择 web 框架的时候有法可依。</p>
<h2 id="WEB-是什么工作的？"><a href="#WEB-是什么工作的？" class="headerlink" title="WEB 是什么工作的？"></a>WEB 是什么工作的？</h2><p>在讨论框架之前，我们要先了解一下网页是怎么工作。我们就从你在浏览器输入一个网址，摁下 enter 键说起。打开你的浏览器，输入 <code>http://jeffknupp.com</code>（译者注：原作者的个人网站首页），我们来看看你的浏览器做了那些事情（DNS 查询的 buffer 就略过），才能显示你看到的网页。</p>
<h3 id="web-servers，和-web-…-servers-…"><a href="#web-servers，和-web-…-servers-…" class="headerlink" title="web servers，和 web … servers …"></a>web servers，和 web … servers …</h3><p>浏览器接接收到的网页都是 <code>HTML</code> 文件，<code>HTML</code> 是一种描述网页内容和结构的语言。负责给浏览器发送 <code>HTML</code> 的程序称为 web server，容易混淆的是，这个应用程序所在的机器通常也被称为 web server。</p>
<p>最重要的一点是，所有的 web 应用做的事情就是把 <code>HTML</code> 内容发送给浏览器。不论这个 web 应用有多么复杂，最终的任务都是把 <code>HTML</code>（我故意忽略掉其他格式的内容，比如 JSON，CSS 文件，因为原理都是一样的）发送给浏览器。</p>
<p>问题来了：web 应用如何知道要发送什么内容给浏览器呢？<strong>答案：它会发送浏览器请求的内容。</strong></p>
<h3 id="HTTP"><a href="#HTTP" class="headerlink" title="HTTP"></a>HTTP</h3><p>浏览器从 web server 下载内容所用的是 <code>HTTP</code> 协议（协议在计算机科学中，指的是双方通信所共同遵循的数据格式和通信步骤）。<code>HTTP</code> 协议的基础是 <code>请求-应答</code> (<code>request-response</code>) 模型。客户端（你的浏览器）<code>请求</code> 某台物理机上 web 应用的数据，web server 则负责 <code>应答</code>请求的数据。</p>
<p>有个重要的事情是：所有的通信都是客户端（你的浏览器）发起的。服务端（web server）是不可能主动连接你，发送没有请求的数据的。如果你收到了数据，只是因为你的浏览器主动请求了这些数据。</p>
<h4 id="HTTP-方法"><a href="#HTTP-方法" class="headerlink" title="HTTP 方法"></a>HTTP 方法</h4><p><code>HTTP</code> 协议的每条消息都有对应的方法（method），不同的方法对应了客户端能发起的不同请求，也对应了客户端不同的意图。比如，<em>请求</em> 网页的 HTML 和提交一个表格在逻辑上是不同的，所以这两种方法需要两种不同的方法。</p>
<h4 id="HTTP-GET"><a href="#HTTP-GET" class="headerlink" title="HTTP GET"></a>HTTP GET</h4><p>顾名思义，<code>GET</code> 方法就是从 web server 获取（get）数据，<code>GET</code> 请求也是目前最常用的 <code>HTTP</code> 请求。 处理 <code>GET</code> 请求的过程中，web 应用只需要返回请求的数据，无需其他操作。尤其是，不应该修改应用的状态（比如， <code>GET</code> 请求不应该导致一个新用户被创建）。因为这个原因，<code>GET</code> 请求通常被看做是 <code>安全</code> 的。</p>
<h4 id="HTTP-POST"><a href="#HTTP-POST" class="headerlink" title="HTTP POST"></a>HTTP POST</h4><p>和网站的交互，明显不只是查看网页的。我们还会通过表格等形式发送数据给 web 应用，这些操作需要用到另外一种请求：<code>POST</code>。<code>POST</code> 请求通常会传递用户创建的信息，导致 web 应用执行某些动作。输入自己的信息，来注册某个网站就会用到 <code>POST</code> 请求，请求中会包含你输入的数据。</p>
<p>和 <code>GET</code> 请求不同的是， <code>POST</code> 请求通常会导致 web 应用状态的改变。上面提及的例子中，表单被提交后，一个新的用户会被创建。还有一点不同，<code>POST</code> 请求的结果可能不会返回 HTML 数据给客户端，客户端需要通过 <code>response code</code> 来判断操作是否成功。</p>
<h4 id="HTTP-response-code"><a href="#HTTP-response-code" class="headerlink" title="HTTP response code"></a>HTTP response code</h4><p>正常情况下，web server 会返回 200 的 response code，意思是：我已经完成了你要我做的事情，并且一切都没有问题。<code>response code</code> 是三位的数字，每次应答都要包含一个 response code，来标识请求的结果。<code>200</code> 表示 OK，是 <code>GET</code> 方法常见的返回值。<code>POST</code> 请求经常会返还 <code>204</code>(No contnet)，表示：一切正常，但是我没有数据可以展示给你。</p>
<p>还需要注意的是：<code>POST</code> 请求发送给的 url，可能和数据发送出去的 url 不同。继续以我们的注册页面为例，注册表可能位于 <code>http://foo.com/signup</code>，点击 <code>submit</code> 之后，包含着注册数据的 <code>POST</code> 请求可能被发送到 <code>http://foo.com/process_signup</code>。<code>POST</code> 请求要发送到的地址，一般在注册表格的 <code>HTML</code> 源码里指定。</p>
<h3 id="Web-应用"><a href="#Web-应用" class="headerlink" title="Web 应用"></a>Web 应用</h3><p>掌握 <code>GET</code> 和 <code>POST</code> 方法就能做很多事情，因为它们是 web 上最常用的两个方法。总结一下，web 应用就是接收 <code>HTTP</code> 请求，然后返回 <code>HTTP</code> 应答，一般是包含请求数据的 <code>HTML</code>。<code>POST</code> 方法会导致 web 应用执行某些动作，例如在数据库添加一条记录。当然还有其他的 <code>HTTP</code> 方法，但目前我们只需要关心 <code>GET</code> 和 <code>POST</code> 就足够啦。</p>
<p>最简单的 web 应用长什么样呢？我们就来写一个监听在 <code>80</code> 端口的 web 应用，一旦和客户端建立连接，就等待客户端发起请求，并返回非常简单的 <code>HTML</code>。</p>
<p>这个程序是这样的：</p>
<pre><code>import socket

HOST = &#39;&#39;
PORT = 80
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
connection, address = listen_socket.accept()
request = connection.recv(1024)
connection.sendall(&quot;&quot;&quot;HTTP/1.1 200 OK
Content-type: text/html


&lt;html&gt;
    &lt;body&gt;
        &lt;h1&gt;Hello, World!&lt;/h1&gt;
    &lt;/body&gt;
&lt;/html&gt;&quot;&quot;&quot;)
connection.close()
</code></pre><p>（如果上面的程序报端口错误，可以把 <code>PORT</code> 的值修改成其他值，比如 <code>8080</code>。）</p>
<p>上面的代码只会接收一个连接和一个请求，不管请求的 URL 是什么，都会返回同样的 <code>HTTP</code> 内容，response code 是 <code>200</code>。（很明显，这不算真正的 web server）。在这个例子，我们告诉客户端，返回的数据格式为 <code>HTML</code>，而不是其他的格式，比如 <code>JSON</code>。</p>
<h4 id="request-请求解析"><a href="#request-请求解析" class="headerlink" title="request 请求解析"></a>request 请求解析</h4><p>如果看一下上面例子中发送的 <code>HTTP</code> 请求（译者注：可以使用 chrome 的 inspect elements -&gt; Network，或者抓包工具 tcpdump 等工具查看发送的 HTTP 请求），就会发现它和应答很相似。请求的第一行是：</p>
<pre><code>&lt;HTTP Method&gt; &lt;URL&gt; &lt;HTTP version&gt;
</code></pre><p>在这个例子里就是 <code>GET / HTTP/1.1</code>。第一行后面跟着的是请求的头部（headers），比如 <code>Accept: */*</code>（表示可以接收任何格式的内容作为应答）。基本上就这么多。</p>
<p>我们发送的应答也是类似的格式，第一行是:</p>
<pre><code>&lt;HTTP version&gt; &lt;HTTP Status-Code&gt; &lt;Status-Code Reason-Phrase&gt;
</code></pre><p>这个例子中就是 <code>HTTP/1.1 200 OK</code>。然后是头部，和请求的头部一样。最后是应答的实际内容。注意：应答也可能是字符串或者二进制对象，头部的 <code>Content-typ</code> 就是来标识应答内容，让客户端来解析的。</p>
<h4 id="web-server-更多琐碎的细节"><a href="#web-server-更多琐碎的细节" class="headerlink" title="web server 更多琐碎的细节"></a>web server 更多琐碎的细节</h4><p>要在上面的例子基础上继续扩展的话，还有很多需要我们来解决的问题：</p>
<ol>
<li>怎么查看请求的 URL，然后返回不同的页面？</li>
<li>除了 <code>GET</code> 请求，怎么处理 <code>POST</code> 请求？</li>
<li>怎么处理很复杂的概念，比如 sessions 和 cookies？</li>
<li>如何扩展这个应用，让它可以同时处理数千条连接？</li>
</ol>
<p>可以想象，没人会愿意每次编写 web 应用的时候都要自己处理这些问题。为了解决这个难题，就会存在很多的软件包帮你处理这些烦人的细节，让开发者可以把心思放到业务逻辑上。记住，不管 web 框架多么负责，其最核心的功能和我们上面的例子是一样的：监听客户端请求，然后返回 <code>HTML</code> 给客户端。</p>
<p>NOTE：客户端的框架和上面的内容迥然不同。</p>
<h3 id="解决两个难题：路由（routing）和模板（templates）"><a href="#解决两个难题：路由（routing）和模板（templates）" class="headerlink" title="解决两个难题：路由（routing）和模板（templates）"></a>解决两个难题：路由（routing）和模板（templates）</h3><p>在构建 web 应用的所有的问题中，有两个比较突出：</p>
<ol>
<li>怎么把请求 URL 和处理它的那部分代码对应起来？</li>
<li>怎么动态地生产请求内容？包括所有要计算的值，和从数据库获取的信息？</li>
</ol>
<p>每个 web 框架解决这两个问题的方法都不太相同，我们就举 Flask 和 Django 的例子来说明这个问题。首先，我们还要来说一下 <code>MVC</code> 模式。</p>
<h3 id="Django-中的-MVC"><a href="#Django-中的-MVC" class="headerlink" title="Django 中的 MVC"></a>Django 中的 MVC</h3><p>Django 采用 MVC 模式， 所以要求使用这个框架的代码都遵循这个模式。<em>MVC</em>，是 <em>Model-View-Controller</em> 的缩写，用来分离应用的不同责任。数据库表所代表的资源用 <em>models</em> 来表示，<em>controllers</em> 负责应用的业务逻辑和操作 models。<em>Views</em> 则负责动态生成代表页面的 <code>HTML</code>。</p>
<p>不过容易让人混淆的是，django 中 <em>controllers</em> 被称作 <em>views</em>，而 <em>views</em> 被称为 <em>templates</em>。除了命名外，django 算是比较直接的 <em>MVC</em> 架构。</p>
<h3 id="Django-的路由（routing）机制"><a href="#Django-的路由（routing）机制" class="headerlink" title="Django 的路由（routing）机制"></a>Django 的路由（routing）机制</h3><p>这里说的路由（routing）就是把请求的 URL 对应到处理生成相关 <code>HTML</code> 的代码。最简单的例子，所有的请求都是相同的代码处理（就是我们之前编写的代码）。复杂一点呢，每个的 URL 都对应一个不同的 <code>view function</code>。比如，有个地方的逻辑是接收到 <code>www.foo.com/bar</code> 请求，就把它交给 <code>handle_bar()</code> 函数处理。我们可以这样依次编写出所有 url 对应的处理函数。</p>
<p>不过，这个方法有个致命伤：没有办法处理带有动态数据的 URL，比如说资源的 ID（例如 <code>http://www.foo.com/users/3</code>）。我们怎么把这个 URL 映射到函数，同时能传过去用户 ID 信息呢？</p>
<p>Django 采用的方法是利用正则表达式：用正则表达式匹配 URL，然后把匹配的数据作为参数传递给处理函数。比如，我可以说匹配 <code>^/users/(?P&lt;id&gt;\d+)/$</code> 的 URL 会调用 <code>display_user(id)</code> 函数，其中 <code>id</code> 就是正则表达式括号里匹配的内容。利用这种方式，任何 <code>/users/&lt;some number&gt;</code> 类型的 URL 都能对应到 <code>display_user</code> 函数，并且正则表达式可以无限复杂，包含任意的关键字和未知参数。</p>
<h3 id="Flask-的-路由机制"><a href="#Flask-的-路由机制" class="headerlink" title="Flask 的 路由机制"></a>Flask 的 路由机制</h3><p>Flask 采用的是另外一种方法。把 url 对应到函数参照的是 <code>route()</code> 装饰器。下面的 Flask 代码和上面提到的正则表达式代码功能相同：</p>
<pre><code>@app.route(&#39;/users/&lt;id:int&gt;/&#39;)
def display_user(id):
    # ...
</code></pre><p>如你所见，装饰器使用的是简化版的正则表达式来传递参数，参数被 route 参数中 <code>&lt;name:type&gt;</code> 的指令捕获。要路由 <code>/info/about.html</code> 这样的页面，就需要 <a href="mailto:`@app.route" target="_blank" rel="noopener">`@app.route</a>(‘/info/about_us.html’)`。</p>
<h3 id="根据模板生成-HTML"><a href="#根据模板生成-HTML" class="headerlink" title="根据模板生成 HTML"></a>根据模板生成 HTML</h3><p>继续上面的例子，一旦我们知道怎么把 URL 对应到逻辑代码，那么要怎么动态地生成 HTML，并且方便开发者手动编辑呢？Django 和 Flask 两者这次方法一样，那就是 —— HTML 模板。</p>
<p><code>HTML 模板</code> 有点像 <code>string.format()</code>：预期的输出首先要用站位标识，然后再填入动态的数据。可以把这个网页想象成一个字符串，里面用括号标识动态的数据，最后调用 <code>str.format()</code> 生成最终的结果。Django 的 模板引擎和 Flask 采用的 <em>jinja2</em> 都是这个原理。</p>
<p>不过，并不是所有的模板引擎地位都一样。Django 的模板只支持简单的变成，而 Jinja2 却能让你执行任意的代码（当然并发完全可以，不过已经很近似）。Jinja2 很会 cache 渲染的结果，下次有同样的参数传过来的时候，就会直接从 cache 获取结果，而不需要重新渲染。</p>
<h3 id="数据库集成"><a href="#数据库集成" class="headerlink" title="数据库集成"></a>数据库集成</h3><p>Django，宣称“自带电池”（batteries included），然后也会包含 <code>ORM</code>（Object Relational Mapper）。<code>ORM</code> 的目的有两个：把 python 的类映射到数据的表结构，和通过封装隐藏不同数据库之间的差异（第一点是它更主要的功能）。没有人喜欢 <code>ORM</code>（因为不同域之间的 mapping 从不完美），不过这些缺点都是可以接受的。 Django 功能比较全面，Flask 作为一个微框架，并不自带 <code>ORM</code>（不过它很好兼容 SQLAlchemy，Django ORM 最大的竞争者）。</p>
<p>因为包含 ORM，Django 能够创建功能齐全的 CRUD 应用。 CRUD（Create Read Update Delete）是 web 框架（服务器端）最美好的地方，Django 和 Flask-SQLAlchemy 使得 CRUD 操作很直接。</p>
<h2 id="Web-框架总结"><a href="#Web-框架总结" class="headerlink" title="Web 框架总结"></a>Web 框架总结</h2><p>写到这，web 框架出现的目的也比较明确了：隐藏基础而又烦人的处理 HTTP 请求和应答的代码。至于要隐藏多少内容，就要看框架啦。Django 和 Flask 代表了两个极端。Django 每种情况都有涉及，而 Flask 标榜自己是“微框架“，只处理 web 程序最核心的功能，依赖其他三方插件来完成其他不常用的工作。</p>
<p>写了这么多，记住，所有的 python web 框架功能方式都一样：它们接收 <code>HTTP</code> 请求，然后分发任务，并生成 HTML，然后返回包含 HTML 的 HTTP 应答。事实上，所有的 server 端框架（除了 Javascript 框架）都是这么工作的。希望，看完这篇文章，你已经知道 web 框架的目的，也知道怎么去选择 web 框架啦。</p>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="通过 free 命令理解 linux 内存管理" href="/2015/10/01/linux-memory-management-through-free/">
        ← 通过 free 命令理解 linux 内存管理
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="python metaclass 入门简介" href="/2015/08/30/metaclass-in-python/">
        python metaclass 入门简介 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#WEB-是什么工作的？"><span class="toc-text">WEB 是什么工作的？</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#web-servers，和-web-…-servers-…"><span class="toc-text">web servers，和 web … servers …</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HTTP"><span class="toc-text">HTTP</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#HTTP-方法"><span class="toc-text">HTTP 方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HTTP-GET"><span class="toc-text">HTTP GET</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HTTP-POST"><span class="toc-text">HTTP POST</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HTTP-response-code"><span class="toc-text">HTTP response code</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Web-应用"><span class="toc-text">Web 应用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#request-请求解析"><span class="toc-text">request 请求解析</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#web-server-更多琐碎的细节"><span class="toc-text">web server 更多琐碎的细节</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#解决两个难题：路由（routing）和模板（templates）"><span class="toc-text">解决两个难题：路由（routing）和模板（templates）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Django-中的-MVC"><span class="toc-text">Django 中的 MVC</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Django-的路由（routing）机制"><span class="toc-text">Django 的路由（routing）机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Flask-的-路由机制"><span class="toc-text">Flask 的 路由机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#根据模板生成-HTML"><span class="toc-text">根据模板生成 HTML</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数据库集成"><span class="toc-text">数据库集成</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Web-框架总结"><span class="toc-text">Web 框架总结</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">【翻译】什么是 web 框架？</div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2015/09/21/what-is-a-web-framework/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2015/09/21/what-is-a-web-framework/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
